package com.jie.other.aidl

import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.DeadObjectException
import android.os.IBinder
import android.os.RemoteException
import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.ToastUtils
import com.jie.commonlib.base.BaseActivity
import com.jie.other.R
import kotlin.random.Random

/**
 * 跨进程通讯AIDL学习页面
 * 参考资料：https://zhuanlan.zhihu.com/p/338093696
 */
class AidlActivity: BaseActivity() {

    private var mTvContent: TextView? = null
    private var mManager: IPersonManager? = null

    /**
     * 远程服务连接
     */
    private val mServiceConnection = object : ServiceConnection{
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            LogUtils.i("onServiceConnected")
            mManager = IPersonManager.Stub.asInterface(service)
            // 给服务设置一个死亡通知
            mManager?.asBinder()?.linkToDeath(mDeathRecipient, 0)
            // 显示初始值
            showPersonContent()
        }

        override fun onServiceDisconnected(name: ComponentName?) {
            LogUtils.i("onServiceDisconnected")
            mManager?.unregisterChangeListener(mChangeListener)
            mManager = null
        }

    }

    /**
     * 数据发生改变监听
     */
    private val mChangeListener = object : IPersonChangeListener.Stub() {

        override fun onDataChange(person: Person?) {
            ToastUtils.showShort(person.toString())
            showPersonContent()
        }

    }

    /**
     * 死亡通知
     */
    private val mDeathRecipient = object :IBinder.DeathRecipient {
        override fun binderDied() {
            LogUtils.i("bind death : ${Thread.currentThread().name}")
            mManager?.asBinder()?.unlinkToDeath(this, 0)
            // 重新连接
            bindPersonService()
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        initActionBar()
        initView()
        bindPersonService()
    }

    override fun onDestroy() {
        super.onDestroy()
        LogUtils.i("onDestroy2:${this}")
        unbindService(mServiceConnection)
    }

    /**
     * 初始化ActionBar
     */
    private fun initActionBar() {
        supportActionBar?.setDisplayHomeAsUpEnabled(true)
        supportActionBar?.setTitle(R.string.other_aidl)
    }

    /**
     * 绑定远程AIDL服务
     */
    private fun bindPersonService() {
        bindService(
            Intent().apply {
//                setPackage("com.jie.other") // 指定包名
                setPackage(packageName)       // 获取当前应用包名
                action = AIDLConstant.PERSON_SERVICE_ACTION
            },
            mServiceConnection,
            Context.BIND_AUTO_CREATE
        )
    }

    private fun initView() {
        setContentView(LinearLayout(this).apply {
            orientation = LinearLayout.VERTICAL
            addView(Button(context).apply {
                text = "SHOW ALL"
                setOnClickListener {
                    showPersonContent()
                }
            })
            addView(Button(context).apply {
                text = "ADD IN"
                setOnClickListener {
                    addPerson(AIDLConstant.TYPE_IN)
                }
            })
            addView(Button(context).apply {
                text = "ADD OUT"
                setOnClickListener {
                    addPerson(AIDLConstant.TYPE_OUT)
                }
            })
            addView(Button(context).apply {
                text = "ADD INOUT"
                setOnClickListener {
                    addPerson(AIDLConstant.TYPE_INOUT)
                }
            })
            addView(Button(context).apply {
                text = "DELAY ADD"
                setOnClickListener {
                    addPerson(AIDLConstant.TYPE_DELAY)
                }
            })
            addView(Button(context).apply {
                text = "CLEAR"
                setOnClickListener {
                    mManager?.clearPerson()
                }
            })
            addView(Button(context).apply {
                text = "Register Listener"
                setOnClickListener {
                    mManager?.registerChangeListener(mChangeListener)
                }
            })
            addView(Button(context).apply {
                text = "Unregister Listener"
                setOnClickListener {
                    mManager?.unregisterChangeListener(mChangeListener)
                }
            })
            addView(Button(context).apply {
                text = "Kill Process"
                setOnClickListener {
                    mManager?.killProcess()
                }
            })
            mTvContent = TextView(context)
            addView(mTvContent)
        })
    }

    /**
     * 添加一个随机数据
     */
    private fun addPerson(type: Int) {
        val index = Random.nextInt(1000)
        //客户端调服务端方法时,需要捕获以下几个异常:
        //RemoteException 异常：
        //DeadObjectException 异常：连接中断时会抛出异常；
        //SecurityException 异常：客户端和服务端中定义的 AIDL 发生冲突时会抛出异常；
        //SecurityException 异常：客户端和服务端中定义的 AIDL 发生冲突时会抛出异常；
        //IllegalStateException 异常：非法状态抛出异常；
        try {
            val person = Person(index, "name$index")
            when(type){
                AIDLConstant.TYPE_IN -> mManager?.addPersonIn(person)
                AIDLConstant.TYPE_OUT -> mManager?.addPersonOut(person)
                AIDLConstant.TYPE_INOUT -> mManager?.addPersonInOut(person)
                AIDLConstant.TYPE_DELAY -> mManager?.delayAddPerson(person)
            }
        } catch (e: RemoteException){
            e.printStackTrace()
        } catch (e: DeadObjectException){
            e.printStackTrace()
        } catch (e: SecurityException){
            e.printStackTrace()
        } catch (e: IllegalStateException){
            e.printStackTrace()
        }
    }

    /**
     * 显示所有数据
     */
    private fun showPersonContent() {
        val contentSb = StringBuilder()
        mManager?.personList?.forEach {
            contentSb.append(it.toString())
            contentSb.append("\n")
        }
        // 由于delayAddPerson方法执行在子线程中，故回调中必须在主线程更新ui
        runOnUiThread {
            mTvContent?.text = contentSb.toString()
        }
    }

}